<script setup lang="ts">
import {h, nextTick, onMounted, ref} from "vue";
import {DropdownOption, NButton, NDataTable, NInput, NProgress, NDropdown} from "naive-ui"
import db from "@/features/db.ts"
import {invoke} from "@tauri-apps/api/core";
import {DownloadInfo} from "#/model.ts";
import {listen} from "@tauri-apps/api/event";
import {formatBytes} from "@/utils";

// const url = ref("https://github.com/microsoft/vscode/archive/refs/tags/1.96.2.zip")
const url = ref("https://dtapp-pub.dingtalk.com/dingtalk-desktop/win_downloader/20241127/dingtalk_downloader.exe")

const xRef = ref(0)
const yRef = ref(0)
const currentItem = ref<DownloadInfo>()
const showDropdownRef = ref(false)
const dataSource = ref<DownloadInfo[]>([])

const columns = [
  {
    title: '名称',
    key: 'name',
    width: 160,
    ellipsis: {
      tooltip: true
    }
  },
  {
    title: 'url',
    key: 'url',
    ellipsis: {
      tooltip: true
    }
  },
  {
    title: '状态',
    key: 'status'
  },
  {
    title: '大小',
    key: 'size',
    render(row: DownloadInfo) {
      return h(
          'div',
          formatBytes(Number(row.size))
      )
    }
  },
  {
    title: '已下载',
    key: 'downloaded_size',
    render(row: DownloadInfo) {
      return h(
          'div',
          formatBytes(Number(row.downloaded_size))
      )
    }
  },
  {
    title: '输出路径',
    key: 'output',
    ellipsis: {
      tooltip: true
    }
  },
  {
    title: '速度',
    key: 'speed',
    ellipsis: {
      tooltip: true
    },
    render(row: DownloadInfo) {
      return h(
          'div',
          formatBytes(Number(row.speed)) + '/s'
      )
    }
  },
  {
    title: '进度',
    key: 'progress',
    render(row: DownloadInfo) {
      return h(
          NProgress,
          {
            type: 'line',
            status: "success",
            indicatorPlacement: "inside",
            percentage: parseFloat(Number(row.progress)?.toFixed(2) || '0'),
          }
      )
    }
  },
  {
    title: '时间',
    key: 'time',
    ellipsis: {
      tooltip: true
    }
  },
]

const options: DropdownOption[] = [
  {
    label: '打开文件',
    key: 'openFile'
  },
  {
    label: '打开文件夹',
    key: 'openFolder'
  },
  {
    label: '删除',
    key: 'delete'
  },
]

const rowProps = (row: DownloadInfo) => {
  return {
    onContextmenu: (e: MouseEvent) => {
      currentItem.value = row
      e.preventDefault()
      showDropdownRef.value = false
      nextTick().then(() => {
        showDropdownRef.value = true
        xRef.value = e.clientX
        yRef.value = e.clientY
      })
    }
  }
}

type KeyValues = (typeof options[number])['key'];
const handleSelect = async (val: KeyValues) => {
  // TODO: 处理右键操作
  showDropdownRef.value = false

  switch (val) {
    case "delete":
      currentItem.value?.id && await db.delDownloadInfo(currentItem.value.id)
      dataSource.value = await db.getList()
      break
    case "openFile":
      await invoke("open_file", {path: currentItem.value?.output})
      break
    case "openFolder":
      await invoke("open_folder", {path: currentItem.value?.output})
      break
  }
}

const download = async () => {
  if (!url.value) return
  await invoke("download", {url: url.value})
}

const init = async () => {
  await db.init()
  dataSource.value = await db.getList()
}

const bindListen = async () => {
  await listen<DownloadInfo>('download-change', async (event) => {
    const info = event.payload
    await db.setDownloadInfo(info)
    const index = dataSource.value.findIndex(item => item.id === info.id)
    if (index > -1) {
      dataSource.value[index] = info
    } else {
      dataSource.value.unshift(info)
    }
  });
}

onMounted(async () => {
  await init()

  await bindListen()
})

</script>

<template>
  <header class="header">
    <n-input type="text" v-model:value="url"></n-input>
    <br>
    <n-button type="primary" @click="download">下载</n-button>
  </header>
  <main class="container">
    <n-data-table
        :columns="columns"
        :data="dataSource"
        :row-props="rowProps"
        :pagination="{pageSize: 8}"
    />
    <n-dropdown
        placement="bottom-start"
        trigger="manual"
        :x="xRef"
        :y="yRef"
        :options="options"
        :show="showDropdownRef"
        :on-clickoutside="() => showDropdownRef = false"
        @select="handleSelect"
    />
  </main>
</template>

<style scoped>
.header {
  padding: 16px;
  display: flex;
  gap: 8px;
  justify-items: center;
  align-items: center;
}

.container {
  padding: 16px;
  font-size: 12px;
}
</style>